package cn.zhqr.core.service;

import cn.zhqr.common.bean.response.ErrorCode;
import cn.zhqr.common.bean.response.OutResponse;
import cn.zhqr.common.external.redis.RedisExt;
import cn.zhqr.common.util.collections.Lists;
import cn.zhqr.common.util.number.SnowflakeIdWorker;
import cn.zhqr.common.util.validate.ParamCheck;
import cn.zhqr.core.bean.WithdrawalParam;
import cn.zhqr.unipay.trans.api.TransChannel;
import cn.zhqr.unipay.trans.api.UniformTransApi;
import cn.zhqr.unipay.trans.api.UniformTransApiFactory;
import cn.zhqr.unipay.trans.param.UniformQueryTransParam;
import cn.zhqr.unipay.trans.param.UniformTransParam;
import cn.zhqr.unipay.trans.response.UniformQueryTransResponse;
import cn.zhqr.unipay.trans.response.UniformTransResponse;
import com.alibaba.fastjson.JSON;
import com.jfinal.ext.plugin.tx.DbTx;
import com.jfinal.ext.plugin.tx.Tx;
import com.jfinal.kit.StrKit;
import org.apache.log4j.Logger;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.List;

public class WithdrawService {
    public static final WithdrawService instance = new WithdrawService();
    private static final Logger logger = Logger.getLogger(WithdrawService.class);

    //提现白名单
    List whiteIdList = Lists.arrayList(10L,11L,1001L);

    /**
     * 发起提现申请
     * @param param
     * @return
     */
    public OutResponse<BigDecimal> applyWithdraw(WithdrawalParam param){
        if(param == null){
            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"传参不正确");
        }
        Long agentId = param.getUserid();
        BigDecimal amount = param.getAmount();
        String bankCardId = param.getBankCardId();

//        if(!whiteIdList.contains(agentId)){
//            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"提现功能正在测试中");
//        }
        if(param.getAmount()==null || param.getAmount().compareTo(BigDecimal.ZERO) <= 0){
            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"提现金额不正确");
        }
        if(agentId==null || agentId <= 0){
            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"商户ID不正确");
        }
        if(StrKit.isBlank(bankCardId)){
            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"银行卡号不正确");
        }

        Agent agent = Agent.dao.findById(agentId);
        if(agent.getAuthType() <= Agent.AUTH_TYPE_UNAUTH){
            return OutResponse.buildError(ErrorCode.UN_AUTH,"请完成实名认证后，再提现");
        }
        AgentInfo agentInfo = AgentInfo.dao.findByAgentId(agentId);
        if(agentInfo == null){
            return OutResponse.buildError(ErrorCode.UN_AUTH,"未查询到认证信息");
        }


        AgentWallet agentWallet = AgentWallet.dao.findByAgentId(agentId);

        BigDecimal availableBalance = agentWallet.getBalance().subtract(agentWallet.getFrozenBalance());
        if(availableBalance.compareTo(amount) < 0){
            return OutResponse.buildError(ErrorCode.BALANCE_NOT_ENOUGH,"账户余额不足");
        }

        //提现风控校验
        WithdrawRiskService.instance.checkWithdraw(agentId,amount);

        String lockResult = RedisExt.use().set("withdraw-lock-"+agentId,"1","NX","EX",10);
        if(!"OK".equalsIgnoreCase(lockResult)){
            return OutResponse.buildError(ErrorCode.OPERATE_TOO_FREQUENT,"请求处理中,请稍后");
        }

        UniformTransApi transApi = UniformTransApiFactory.getInstance(TransChannel.BAOFU);

        SnowflakeIdWorker worker = new SnowflakeIdWorker(1);
        long transNo = worker.nextId();

        UniformTransParam transParam = new UniformTransParam();
        transParam.setTransNo(""+transNo);

        AgentBankCard bankCard = AgentBankCard.dao.findById(bankCardId);
        if(bankCard == null || !bankCard.getAgentId().equals(agentId)){
            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"该卡号未绑定");
        }

        transParam.setMoney(amount.toString());
        transParam.setAccountName(bankCard.getAccountName());
        transParam.setAccountNo(bankCard.getBankCardNo());
        transParam.setBankName(bankCard.getBankName());
        transParam.setIdCardNo(agentInfo.getIdCardNo());
        transParam.setSummary("手动提现至银行卡");

        if(bankCard.getType() == AgentBankCard.TYPE_COMPANY){
            if(bankCard.getType()==AgentBankCard.TYPE_COMPANY){
                if(!bankCard.getAccountName().equals(agentInfo.getCompName())){
                    return OutResponse.buildError(ErrorCode.INVALID_PARAM,"户名与企业名称不一致");
                }
            }else{
                if(!bankCard.getAccountName().equals(agentInfo.getPersonName())){
                    return OutResponse.buildError(ErrorCode.INVALID_PARAM,"户名与法人姓名不一致");
                }
            }

            transParam.setSubBrandNo(bankCard.getSubBranchNo());
        }else{
            if(!bankCard.getAccountName().equals(agentInfo.getPersonName())){
                return OutResponse.buildError(ErrorCode.INVALID_PARAM,"户名与实名认证姓名不一致");
            }
        }

        logger.error("提现入参："+ JSON.toJSONString(transParam));
        UniformTransResponse transResp = transApi.transToBank(transParam);
        logger.error("提现结果："+JSON.toJSONString(transResp));

//        com.thoughtworks.xstream.converters.collections.TreeMapConverter
//        java.lang.NoClassDefFoundError: Could not initialize class

        if(!transResp.isSuccess()){
            return OutResponse.buildError(ErrorCode.INVALID_PARAM,"提现失败："+transResp.getMsg());
        }


        OutResponse[] result = new OutResponse[1];
        DbTx.execute(new Tx() {
            @Override
            public void sql() {
                WithdrawOrder withdrawOrder = new WithdrawOrder();
                withdrawOrder.setAgentId(agentId);
                withdrawOrder.setAmount(amount);
                withdrawOrder.setStatus(WithdrawOrder.STATUS_WAITING);
                withdrawOrder.setOrderNo(BigInteger.valueOf(transNo));
                withdrawOrder.setAgentId(agentId);
                withdrawOrder.setCreateTime(new Date());
                withdrawOrder.setRemark(param.getDesc());
                withdrawOrder.save();

                AgentFrozenTradeService.instance.freeze(agentId,amount, AgentFrozenTrade.TYPE_WITHDRAW_FREEZE,withdrawOrder.getOrderNo());

                result[0] = OutResponse.buildSuccess("提现申请已提交",null);
            }

            @Override
            public void error(Exception e) {
                logger.error("withdraw transaction error:",e);
                result[0] = OutResponse.buildError(ErrorCode.PAY_FAILED,"提现申请已提交");
            }
        });

        return result[0];
    }


    /**
     * 查询并尝试更新提现订单状态
     * @param order
     */
    public void queryAndUpdateWithdrawState(WithdrawOrder order){
        if(order == null){
            logger.error("queryWithdrawResult order is null");
            return ;
        }

        String transNo = order.getOrderNo().toString();
        ParamCheck.isNotBlank(transNo,"单号不能为空");

        UniformTransApi transApi = UniformTransApiFactory.getInstance(TransChannel.BAOFU);
        UniformQueryTransParam queryTransParam = new UniformQueryTransParam();
        queryTransParam.setTransNo(transNo);

        UniformQueryTransResponse res = transApi.queryTransResult(queryTransParam);

        logger.error("queryWithdrawResult  param:"+JSON.toJSONString(queryTransParam)+" result："+JSON.toJSONString(res));

        if(!res.isSuccess()){
            logger.error("queryWithdrawResult error："+res.getMsg());
            return;
        }

        String state = res.getTransState();
        if(UniformQueryTransResponse.STATUS_SUCCESS.equals(state)){
            order.setStatus(WithdrawOrder.STATUS_SUCCESS);
            order.update();

            DbTx.execute(new Tx() {
                @Override
                public void sql() {
                    AgentWallet.dao.increaseBalance(order.getAgentId(),order.getAmount().negate());

                    AgentTrade agentTrade = new AgentTrade();
                    agentTrade.setAgentId(order.getAgentId());
                    agentTrade.setAmount(order.getAmount().negate());
                    agentTrade.setBalance(AgentWallet.dao.findBalanceByAgentId(order.getAgentId()));
                    agentTrade.setTradeType(AgentTrade.TYPE_WITHDRAW);
                    agentTrade.setCreateTime(new Date());
                    agentTrade.save();

                    AgentFrozenTradeService.instance.unfreeze(order.getOrderNo());
                }

                @Override
                public void error(Exception e) {
                    logger.error("queryWithdrawResult transaction error:",e);
                }
            });
        }else if(UniformQueryTransResponse.STATUS_FAILED.equals(state) || UniformQueryTransResponse.STATUS_FAILED_REFUND.equals(state)){
            order.setStatus(WithdrawOrder.STATUS_FAILED);
            order.setMsg(res.getTransDesc());
            order.update();

            AgentFrozenTradeService.instance.unfreeze(order.getOrderNo());
        }
    }
}
